#include <iostream>
#include "ston_log.h"
#include "ston_dbc.h"

// Needed for threading
#include <rw/thr/thrfunc.h>

class Problem {
public:
    Problem() {
        //StonDBC::keepAlive(); // [TEST] (Un)Comment to define dependencies of this object
        //StonLog::keepAlive(); // [TEST] (Un)Comment to define dependencies of this object
        std::cout << "Problem born\n";
    }
    ~Problem() {
        StonDBC::getInstance(); // [TEST] (Un)Comment to use / not use singleton
        //StonLog::getInstance(); // [TEST] (Un)Comment to use / not use singleton
        std::cout << "Problem died\n";
    }
};

//Problem prob; // [TEST] (Un)Comment to create / not create static object that possibly uses singletons

// Forward declarations
void testST();
void testMT();
void testMTFunc();

int main() {
    std::cout << "=====[ Startup ]=====\n";
    srand(time(0));
    // [NOTE] For multi-threaded tests you'll probably want to put some rwSleep()s inside the Manager class in use
    bool mt = true; // [TEST] Change to define single-threaded / multi-threaded test
    if(!mt) testST();
    else testMT();
    std::cout << "=====[ Shutdown ]=====\n";
}

void testST() {
    for (int i = 0; i < 10; ++i) {
        if(rand() % 2) StonDBC::getInstance()->doUse();
        else           StonLog::getInstance()->doUse();
    }
}

void testMT() {
    RWThreadFunction t1 = rwMakeThreadFunction(testMTFunc);
    RWThreadFunction t2 = rwMakeThreadFunction(testMTFunc);
    RWThreadFunction t3 = rwMakeThreadFunction(testMTFunc);
    RWThreadFunction t4 = rwMakeThreadFunction(testMTFunc);
    RWThreadFunction t5 = rwMakeThreadFunction(testMTFunc);
    t1.start(); t2.start(); t3.start(); t4.start(); t5.start();
    t1.join();  t2.join();  t3.join();  t4.join();  t5.join();
}

void testMTFunc() {
    for (int i = 0; i < 2; ++i) {
        if(rand() % 2) rwSleep(1);
        if(rand() % 2) StonDBC::getInstance()->doUse();
        else           StonLog::getInstance()->doUse();
    }
}
